package cplus_cplus_std

import (
	"errors"
)

// Vector 泛型向量容器
type Vector[T any] struct {
	data []T // 底层数据
	cap  int // 容量
	len  int // 当前长度
}

// New 创建一个新的Vector，初始容量为cap
func MakeVectorObj[T any](cap int) *Vector[T] {
	if cap < 0 {
		cap = 0
	}
	return &Vector[T]{
		data: make([]T, cap),
		cap:  cap,
		len:  0,
	}
}

// Len 返回当前元素数量
func (v *Vector[T]) Size() int {
	return v.len
}

// Cap 返回当前容量
func (v *Vector[T]) Cap() int {
	return v.cap
}

// Empty 判断是否为空
func (v *Vector[T]) Empty() bool {
	return v.len == 0
}

// At 返回指定位置的元素
func (v *Vector[T]) Find(index int) (T, error) {
	var zero T
	if index < 0 || index >= v.len {
		return zero, errors.New("index out of range")
	}
	return v.data[index], nil
}

// Front 返回第一个元素
func (v *Vector[T]) Front() (T, error) {
	return v.Find(0)
}

// Back 返回最后一个元素
func (v *Vector[T]) Back() (T, error) {
	return v.Find(v.len - 1)
}

// PushBack 在尾部添加元素
func (v *Vector[T]) PushBack(value T) {
	if v.len >= v.cap {
		v.resize()
	}
	v.data[v.len] = value
	v.len++
}

// PopBack 移除最后一个元素
func (v *Vector[T]) PopBack() error {
	if v.Empty() {
		return errors.New("vector is empty")
	}
	v.len--
	// 帮助GC
	var zero T
	v.data[v.len] = zero
	return nil
}

// Clear 清空所有元素
func (v *Vector[T]) Clear() {
	// 帮助GC
	for i := 0; i < v.len; i++ {
		var zero T
		v.data[i] = zero
	}
	v.len = 0
}

// Resize 调整元素数量
func (v *Vector[T]) Resize(newSize int) {
	if newSize < 0 {
		newSize = 0
	}

	if newSize > v.cap {
		v.resizeTo(newSize)
	}

	// 帮助GC：如果缩小尺寸，清空多余元素
	for i := newSize; i < v.len; i++ {
		var zero T
		v.data[i] = zero
	}
	v.len = newSize
}

// Reserve 调整容量
func (v *Vector[T]) Reserve(newCap int) {
	if newCap > v.cap {
		v.resizeTo(newCap)
	}
}

// 自动扩容（两倍增长）
func (v *Vector[T]) resize() {
	if v.cap == 0 {
		v.resizeTo(1)
	} else {
		v.resizeTo(v.cap * 2)
	}
}

// 调整到指定容量
func (v *Vector[T]) resizeTo(newCap int) {
	newData := make([]T, newCap)
	copy(newData, v.data)
	v.data = newData
	v.cap = newCap
}

// Slice 返回底层切片的副本--会拷贝
func (v *Vector[T]) Slice() []T {
	return append([]T(nil), v.data[0:v.len]...)
}
